package cn.maihe.elg.operation.supports.system;

import cn.maihe.elg.operation.config.ElgConfig;
import cn.maihe.elg.operation.config.ElgResourceConfig;
import cn.maihe.elg.operation.exception.ErrorCode;
import cn.maihe.elg.operation.exception.SystemRuntimeException;
import cn.maihe.elg.operation.model.bo.ApplyTemplatePdfParams;
import cn.maihe.elg.operation.model.bo.GuaranteeTemplatePdfParams;
import cn.maihe.elg.operation.model.bo.ReceiveTemplatePdfParams;
import cn.maihe.elg.operation.model.enums.AttachmentFileType;
import cn.maihe.elg.operation.repository.entity.GuaranteeAttachmentInfoDO;
import cn.maihe.elg.operation.repository.entity.GuaranteeAttachmentInfoDOCondition;
import cn.maihe.elg.operation.service.order.GuaranteeAttachmentInfoService;
import cn.maihe.elg.operation.utils.DocFillUtil;
import cn.maihe.elg.operation.utils.ElgLogger;
import cn.maihe.elg.operation.utils.IdGenerate;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.DigestUtils;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.net.ssl.*;
import java.io.*;
import java.net.*;
import java.nio.channels.Channels;
import java.io.InputStream;
import java.nio.channels.ReadableByteChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.security.cert.X509Certificate;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Base64;
import java.util.Map;

/**
 * @Description
 * @Author WJH
 * @Date 2021/04/26
 */
@Service
@Slf4j
public class ElgResourceService {

    private ElgResourceConfig resourceConfig;

    final String DOC_SUBTYPE = "msword";
    final String DOCX_SUBTYPE = "vnd.openxmlformats-officedocument.wordprocessingml.document";
    final String XLS_SUBTYPE = "vnd.ms-excel application/x-excel";
    final String XLSX_SUBTYPE = "vnd.openxmlformats-officedocument.spreadsheetml.sheet";
    final String OCTET_STREAM_SUBTYPE = "octet-stream";
    public static final String noAuthDownloadPath = "/api/attachment/download/guarantee";
    public static final String ofdDownloadPath = "/api/attachment/download/getOFD";


    @Resource
    private RestTemplate restTemplate;

    @Resource
    private ElgConfig elgConfig;

    @Resource
    private GuaranteeAttachmentInfoService guaranteeAttachmentInfoService;


    public ElgResourceService(ElgResourceConfig resourceConfig) {
        this.resourceConfig = resourceConfig;
    }

    /**
     * 保存 电子保单相关文件
     *
     * @param srcPath
     * @param acceptOrderNo
     * @return 相对basePath路径，db存储
     */
    public String save2OfdPath(Path srcPath, String acceptOrderNo, String fileName) {
        try {
            String fileType = getFileType(srcPath);
            Path curSaveOfdPath = buildSaveAbsolutePath(resourceConfig.getOfdPath(), acceptOrderNo, fileName, fileType);
            Files.copy(srcPath, curSaveOfdPath, StandardCopyOption.REPLACE_EXISTING);
            return resourceConfig.getRelativePath(curSaveOfdPath);
        } catch (Exception e) {
            throw new RuntimeException("保存文件异常:" + e.getMessage(), e);
        }
    }

    public String buildOfdPath(Path srcPath, String acceptOrderNo, String fileName) {
        String fileType = getFileType(srcPath);
        Path curSaveOfdPath = buildSaveAbsolutePath(resourceConfig.getOfdPath(), acceptOrderNo, fileName, fileType);
        return curSaveOfdPath.toString();
    }

    public Path buildOfdPath(String acceptOrderNo, String fileName, String fileType) {
        Path curSaveOfdPath = buildSaveAbsolutePath(resourceConfig.getOfdPath(), acceptOrderNo, fileName, fileType);
        return curSaveOfdPath;
    }


    /**
     * 根据 保存db相对路径获取文件
     *
     * @param relativePath
     * @return
     */
    public File getFileByRelativePath(String relativePath) {
        Path absolutePath = resourceConfig.getAbsolutePath(relativePath);
        if (Files.notExists(absolutePath) || absolutePath.toFile().length() <= 0) {
            throw new RuntimeException("查无此文件或文件大小为0");
        }
        return absolutePath.toFile();
    }

    public File getTempTestFile() {
        return getFileByRelativePath("/tmp/test.ofd");
    }

    /**
     * 构建子目录文件 basePath/curDate/subPath/srcPath.getFileName
     *
     * @param subPath  yml定义的子目录
     * @param curDir   保存目录
     * @param fileName 保存文件名称 不包含文件类型
     * @return
     */
    public Path buildSaveAbsolutePath(String subPath, String curDir, String fileName, String fileType) {

        String curSaveOfdPath = subPath + File.separator + curDir;
        Path curAbsolutePath = Paths.get(resourceConfig.getBasePath(), curSaveOfdPath);
        if (Files.notExists(curAbsolutePath)) {
            try {
                Files.createDirectories(curAbsolutePath);
            } catch (IOException e) {
                throw new RuntimeException("创建目录异常:" + e.getMessage());
            }
        }

        Path curSaveOfdFile = Paths.get(curAbsolutePath.toString(), fileName + "." + fileType);
        return curSaveOfdFile;
    }

    /**
     * 转换保存文件并返回 保存db的相对路径
     */
    public String transferAndSaveFile(Path srcPath, String subPath, String curDir, String fileName) {
        try {
            String fileNameWithoutExt = stripExtension(fileName);
            Path curSaveOfdPath = save(srcPath, subPath, curDir, fileNameWithoutExt);
            return resourceConfig.getRelativePath(curSaveOfdPath);
        } catch (Exception e) {
            throw new RuntimeException("保存文件异常:" + e.getMessage(), e);
        }
    }

    /**
     * 转换保存文件并返回 保存db的相对路径
     */
    public String transferAndSaveFile(MultipartFile multipartFile, String subPath, String curDir, String fileName) {
        try {
            String fileNameWithoutExt = stripExtension(fileName);
            Path curSaveOfdPath = save(multipartFile, subPath, curDir, fileNameWithoutExt);
            return resourceConfig.getRelativePath(curSaveOfdPath);
        } catch (Exception e) {
            throw new RuntimeException("保存文件异常:" + e.getMessage(), e);
        }
    }
    //返回相对路径
    public String relativePath (MultipartFile multipartFile, String subPath, String curDir, String fileName) {
        try {
            String fileNameWithoutExt = stripExtension(fileName);
            Path curSaveOfdPath = save(multipartFile, subPath, curDir, fileNameWithoutExt);
            return resourceConfig.getPath(curSaveOfdPath);
        } catch (Exception e) {
            throw new RuntimeException("保存文件异常:" + e.getMessage(), e);
        }
    }
    public String relativePath (Path path, String subPath, String curDir, String fileName) {
        try {
            String fileNameWithoutExt = stripExtension(fileName);
            Path curSaveOfdPath = save(path, subPath, curDir, fileNameWithoutExt);
            return resourceConfig.getPath(curSaveOfdPath);
        } catch (Exception e) {
            throw new RuntimeException("保存文件异常:" + e.getMessage(), e);
        }
    }
    private Path save(Path path,String subPath, String curDir, String fileName) throws IOException {
        Path curSaveOfdPath = buildSaveAbsolutePath(subPath, curDir, fileName, getFileType(path));
        Files.copy(path, curSaveOfdPath, StandardCopyOption.REPLACE_EXISTING);
        return curSaveOfdPath;
    }
    private Path save(MultipartFile multipartFile,String subPath, String curDir, String fileName) throws IOException {
        Path curSaveOfdPath = buildSaveAbsolutePath(subPath, curDir, fileName, getFileType(multipartFile.getOriginalFilename()));
        Files.copy(multipartFile.getInputStream(), curSaveOfdPath, StandardCopyOption.REPLACE_EXISTING);
        return curSaveOfdPath;
    }
    private String stripExtension(String fileName) {
        if (fileName == null) {
            return null;
        }
        int lastDotIndex = fileName.lastIndexOf('.');
        return (lastDotIndex == -1) ? fileName : fileName.substring(0, lastDotIndex);
    }
    public String getRelativePath(Path absolutePath) {
        return resourceConfig.getRelativePath(absolutePath);
    }

    public Path getAbsolutePath(String relativePath) {
        return resourceConfig.getAbsolutePath(relativePath);
    }

    public String getFileType(Path path) {
        return getFileType(path.getFileName().toString());
    }

    public String getFileName(Path path) {
        return getFileName(path.getFileName().toString());
    }

    public String getFileNameAndType(Path path) {
        return path.getFileName().toString();
    }

    /**
     * @param originalFilename abc.fileType
     * @return
     */
    public String getFileType(String originalFilename) {
        return originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
    }

    /**
     * 不带类型
     *
     * @param originalFilename
     * @return
     */
    public String getFileName(String originalFilename) {
        return originalFilename.substring(0, originalFilename.lastIndexOf("."));
    }

    /**
     * 文件md5值 hex小写字符
     *
     * @param path
     * @return
     */
    public String getFileMD5AsHex(Path path) {
        try {
            return DigestUtils.md5DigestAsHex(Files.readAllBytes(path)).toUpperCase();
        } catch (IOException e) {
            throw new RuntimeException("获取文件md5异常：" + e.getMessage(), e);
        }
    }

    /**
     * 根据excel模板名称获取path
     *
     * @param templateFileName
     * @return
     */
    public Path getExcelTemplatePath(String templateFileName) {
        Path excelTemplatePate = getAbsolutePath(resourceConfig.getExcelTemplate() + File.separator + templateFileName);
        if (Files.notExists(excelTemplatePate) || excelTemplatePate == null) {
            throw new RuntimeException(String.format("查无此excel模板文件[%s/%s/%s]", resourceConfig.getBasePath(), resourceConfig.getExcelTemplate(), templateFileName));
        }
        return excelTemplatePate;
    }

    /**
     * 下载url文件并临时保存
     */
    public Path downloadByURL(String remoteUrl) {

        ResponseEntity<byte[]> responseEntity = null;
        try {
            responseEntity = restTemplate.getForEntity(remoteUrl, byte[].class);
        } catch (RestClientException e) {
            throw new RuntimeException("下载文件失败:" + e.getMessage(), e);
        }
        if (responseEntity.getStatusCode().is2xxSuccessful()) {
            HttpHeaders httpHeaders = responseEntity.getHeaders();
            String fileName = httpHeaders.getContentDisposition().getFilename();
            if (fileName == null) {
                fileName = IdGenerate.getIdStr() + "." + getFileType(httpHeaders.getContentType());
            } else {
                try {
                    fileName = URLDecoder.decode(fileName, "utf-8");
                } catch (Exception e) {
                    fileName = IdGenerate.getIdStr() + "." + getFileType(httpHeaders.getContentType());
                }
            }
            try {
                Path tmpPath = Files.createTempFile("", fileName);
                byte[] bytes = responseEntity.getBody();
                //前50个字节中包含status字符则视为下载失败的错误信息提示
                byte[] tmpAy = Arrays.copyOf(bytes, Math.min(bytes.length, 50));
                if (new String(tmpAy).toLowerCase().contains("status")) {
                    Map<String, String> errorMsg = JSON.parseObject(bytes, Map.class);
                    throw new RuntimeException(String.format("[%s:%s]", errorMsg.get("status"), errorMsg.get("msg")));
                }
                return Files.write(tmpPath, bytes);
            } catch (IOException e) {
                throw new RuntimeException("下载保存文件失败:"+e.getMessage(), e);
            }
        } else {
            throw new RuntimeException("下载文件失败httpStatus:"+responseEntity.getStatusCode());
        }

    }

    /**
     * 将字节数据存储到本地
     */
    public Path byte2LocalFile(byte[] bytes, String fileName) {
        try {
            Path tmpPath = Files.createTempFile("", fileName);
            //前50个字节中包含status字符则视为下载失败的错误信息提示
            byte[] tmpAy = Arrays.copyOf(bytes, Math.min(bytes.length, 50));
            if (new String(tmpAy).toLowerCase().contains("status")) {
                Map<String, String> errorMsg = JSON.parseObject(bytes, Map.class);
                throw new RuntimeException(String.format("[%s:%s]", errorMsg.get("status"), errorMsg.get("msg")));
            }
            return Files.write(tmpPath, bytes);
        } catch (IOException e) {
            throw new RuntimeException(MessageFormat.format("下载保存文件失败:{}", e.getMessage(), e));
        }
    }

    /**
     * 禁用证书校验
     * @throws Exception
     */
    private void trustAllCertificates() throws Exception {
        TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return null;
            }

            public void checkClientTrusted(X509Certificate[] certs, String AuthType) {
            }

            public void checkServerTrusted(X509Certificate[] certs, String AuthType) {
            }
        }};

        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, new java.security.SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

        // Create all-trusting host name verifier
        HostnameVerifier allHostsValid = new HostnameVerifier() {
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        };

        // Install the all-trusting verifier
        HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
    }

    /**
     * 通过http url下载文件
     * @param remoteUrl
     * @return
     */
    public Path downloadFile(String remoteUrl) {
        try {
            trustAllCertificates(); // 禁用证书校验 (仅用于测试!)
        } catch (Exception e) {
            System.err.println("禁用证书校验失败: " + e.getMessage());
            e.printStackTrace();
            // 在生产环境中，应该抛出异常或采取其他处理方式
            // 例如：throw new IOException("Failed to trust certificates", e);
        }
        URL url = null;
        try {
            url = new URL(remoteUrl);
        } catch (MalformedURLException e) {
            throw new RuntimeException(e);
        }
        String fileName = getFileNameFromUrl(url);

        // 尝试从 URL 连接的 Content-Type 头部获取文件类型
        String contentType = null;
        try {
            HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
            contentType = connection.getContentType();
            fileName = connection.getHeaderField("Content-Disposition"); // 获取 Content-Disposition 头部

            // 如果 Content-Disposition 头部存在，则从中提取文件名
            if (fileName != null) {
                // Content-Disposition 格式可能为：
                // attachment; filename="filename.jpg"
                // attachment; filename=filename.jpg
                int fileNameStartIndex = fileName.indexOf("filename=");
                if (fileNameStartIndex > 0) {
                    fileName = fileName.substring(fileNameStartIndex + 9); // 提取文件名部分
                    fileName = fileName.replaceAll("\"", ""); // 移除引号（如果存在）
                }
            }
        } catch (IOException e) {
            System.err.println("无法获取 Content-Type 头部: " + e.getMessage());
        }

        // 如果 Content-Type 头部为空，则尝试从文件名中推断文件类型
        String fileExtension = null;
        if (contentType != null) {
            // 从 Content-Type 头部解析文件扩展名 (需要根据实际情况处理)
            // 例如：contentType 可能为 "image/jpeg;charset=UTF-8"
            if (contentType.startsWith("image/")) {
                fileExtension = ".jpg"; // 假设为 JPEG 图片
            } else if (contentType.startsWith("application/pdf")) {
                fileExtension = ".pdf";
            } // 添加其他常见的文件类型映射
        } else if (fileName != null) {
            fileExtension = FilenameUtils.getExtension(fileName);
            if (fileExtension != null && !fileExtension.isEmpty()) {
                fileExtension = "." + fileExtension; // 添加点号前缀
            }
        }

        // 构建完整的文件名，包含扩展名
        if (fileExtension != null) {
            fileName += fileExtension;
        } else {
            fileName += ".pdf"; // 默认扩展名
        }
        Path targetPath = null;
        try {
            targetPath = Files.createTempFile("", fileName);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
//        Path targetPath = Paths.get(fileName);

        try (InputStream in = url.openStream()) {
            Files.copy(in, targetPath, StandardCopyOption.REPLACE_EXISTING);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        return targetPath;
    }

    private String getFileNameFromUrl(URL url) {
        String path = url.getPath();
        String fileName = path.substring(path.lastIndexOf('/') + 1);
        // 查找最后一个点号的位置
        int lastDotIndex = fileName.lastIndexOf('.');
        // 如果存在点号，则去除后缀
        if (lastDotIndex > 0) {
            fileName = fileName.substring(0, lastDotIndex);
        }
        if (fileName.isEmpty()) {
            // 从URL query 参数中获取文件名
            String query = url.getQuery();
            if (query != null && !query.isEmpty()) {
                String[] params = query.split("&");
                for (String param : params) {
                    // 查找第一个等号的位置
                    int equalsIndex = param.indexOf('=');
                    // 如果存在等号，则截取参数名和参数值
                    if (equalsIndex > 0) {
                        String paramName = param.substring(0, equalsIndex);
                        String encodedFileName = paramName.substring(equalsIndex + 1);
                        // 注意：这里需要根据实际情况进行URL解码
                        // 例如使用 java.net.URLDecoder.decode(encodedFileName, "UTF-8")
                        // 解码后得到的文件名可能需要进一步处理，例如去除特殊字符等
                        return encodedFileName; // 替换为解码后的文件名
                    }
                }
            }
            return "downloaded_file"; // 默认文件名
        }
        return fileName;
    }

//    private static String getFileExtension(String url) throws Exception {
//        if (url.lastIndexOf(".") > 0) {
//            return url.substring(url.lastIndexOf(".")).replaceAll("\"", "");
//        } else {
////            return FileTypeUtil.getType(new URL(url).openStream());
//            return null;
//        }
//    }

    public String getFileType(MediaType mediaType) {

        String type = mediaType.getType();
        String subType = mediaType.getSubtype();
        //图片类型
        if ("image".equalsIgnoreCase(type)) {
            return mediaType.getSubtype();
        }

        //文本类型
        if ("text".equalsIgnoreCase(type)) {
            if ("plain".equalsIgnoreCase(subType)) {
                return "txt";
            }
            if ("javascript".equalsIgnoreCase(subType)) {
                return "js";
            }
            return subType;
        }
        //应用类型 仅识别常用的，其他取字面类型
        if ("application".equalsIgnoreCase(type)) {
            if ("pdf".equalsIgnoreCase(subType) || "ofd".equalsIgnoreCase(subType)) {
                return subType;
            }
            if (DOC_SUBTYPE.equalsIgnoreCase(subType)) {
                return "doc";
            }
            if (DOCX_SUBTYPE.equalsIgnoreCase(subType)) {
                return "docx";
            }
            if (XLS_SUBTYPE.equalsIgnoreCase(subType)) {
                return "xls";
            }
            if (XLSX_SUBTYPE.equalsIgnoreCase(subType)) {
                return "xlsx";
            }
            //todo:alan 此处octet-stream类型对应的文件为edc格式
            if (OCTET_STREAM_SUBTYPE.equalsIgnoreCase(subType)) {
                return "edc";
            }
        }
        //其他默认直接返回 subType
        return mediaType.getSubtype();
    }

    public String fmtNoAuthDownloadUrl(String relativeUri) {
        String apiBaseUrl = elgConfig.getApiBaseUrl();
        if (StringUtils.isNotBlank(relativeUri) && StringUtils.isNotBlank(apiBaseUrl)) {
            try {
                if (apiBaseUrl.endsWith("/")) {
                    apiBaseUrl = apiBaseUrl.substring(0, apiBaseUrl.length() - 1);
                }
                relativeUri = this.encodeRelativeURI(relativeUri);
                return String.format("%s%s?relativeURI=%s", apiBaseUrl, noAuthDownloadPath, relativeUri);
            } catch (Exception e) {
                throw new RuntimeException("转换下载地址异常:" + e.getMessage());
            }
        }
        throw new RuntimeException("转换相对地址不能为空");
    }
    public String ofdDownloadUrl(String relativeUri) {
        String apiBaseUrl = elgConfig.getApiBaseUrl();
        if (StringUtils.isNotBlank(relativeUri) && StringUtils.isNotBlank(apiBaseUrl)) {
            try {
                if (apiBaseUrl.endsWith("/")) {
                    apiBaseUrl = apiBaseUrl.substring(0, apiBaseUrl.length() - 1);
                }
                return String.format("%s%s?relativeURI=%s", apiBaseUrl, ofdDownloadPath, relativeUri);
            } catch (Exception e) {
                throw new RuntimeException("转换通用下载地址异常:" + e.getMessage());
            }
        }
        throw new RuntimeException("转换相对地址不能为空");
    }

    /**
     * @param acceptOrderNo
     * @param attachmentFileType
     * @return Base64.getUrlEncoder.encode(spId_acceptOrderNo_fileType)
     */
    private String fmtEncodeSpIdRelativeUri(String acceptOrderNo, AttachmentFileType attachmentFileType) {
        String acceptOrderNo_fileType = String.format("%s_%s", acceptOrderNo, attachmentFileType.getType());
        return "spId_" + encodeRelativeURI(acceptOrderNo_fileType);
    }

    public String encodeRelativeURI(String decodeRelativeURI) {
        return Base64.getUrlEncoder().encodeToString(decodeRelativeURI.getBytes(StandardCharsets.UTF_8));
    }

    public String decodeRelativeURI(String encodeRelativeURI) {
        return new String(Base64.getUrlDecoder().decode(encodeRelativeURI), StandardCharsets.UTF_8);
    }

    /**
     * @param enCodeRelativeURI urlEncode编码过的先对路径
     * @return
     */
    public Path getPathByEncodeRelativeURI(String enCodeRelativeURI) {
        Path filePath = null;
        if (enCodeRelativeURI.startsWith("spId_")) {
            String encodeAcceptOrderNoFileType = enCodeRelativeURI.substring("spId_".length());
            String decodeAcceptOrderNoFileType = decodeRelativeURI(encodeAcceptOrderNoFileType);
            String[] sAy = decodeAcceptOrderNoFileType.split("_");
            if (sAy.length >= 2) {
                String acceptOrderNo = sAy[0];
                Integer attachmentFileType = Integer.parseInt(sAy[1]);
                GuaranteeAttachmentInfoDO attachmentInfoDO = guaranteeAttachmentInfoService.selectOne(GuaranteeAttachmentInfoDOCondition.builder().andAcceptOrderNoEq(acceptOrderNo).andTypeEq(attachmentFileType).build());
                if (attachmentInfoDO == null) {
                    throw new SystemRuntimeException(ErrorCode.ERROR, "查无此文件");
                }
                filePath = this.getFileByRelativePath(attachmentInfoDO.getFilePath()).toPath();
            } else {
                throw new RuntimeException("下载参数有误");
            }
        } else {
            String decodeRelativeURI = this.decodeRelativeURI(enCodeRelativeURI);
            filePath = this.getFileByRelativePath(decodeRelativeURI).toPath();
        }

        return filePath;
    }

    public String fmtSpIdNoAuthDownloadUrl(String acceptOrderNo, AttachmentFileType attachmentFileType) {
        String apiBaseUrl = elgConfig.getApiBaseUrl();
        Assert.notNull(attachmentFileType, () -> "附件类型不能为空");
        if (StringUtils.isNotBlank(acceptOrderNo) && StringUtils.isNotBlank(apiBaseUrl)) {
            try {
                if (apiBaseUrl.endsWith("/")) {
                    apiBaseUrl = apiBaseUrl.substring(0, apiBaseUrl.length() - 1);
                }
                String relativeUri = this.fmtEncodeSpIdRelativeUri(acceptOrderNo, attachmentFileType);
                return String.format("%s%s?relativeURI=%s", apiBaseUrl, noAuthDownloadPath, relativeUri);
            } catch (Exception e) {
                throw new RuntimeException("转换下载地址异常:" + e.getMessage());
            }
        }
        throw new RuntimeException("转换相对地址不能为空");
    }

    /**
     * 前端完整请求地址
     *
     * @param appendUrl
     * @return
     */
    public String buildElgFrontUrl(String appendUrl) {
        String homeBaseUrl = elgConfig.getHomeBaseUrl();
        if (homeBaseUrl.endsWith("/")) {
            homeBaseUrl = homeBaseUrl.substring(0, homeBaseUrl.length() - 1);
        }
        if (!appendUrl.startsWith("/")) {
            appendUrl = "/" + appendUrl;
        }
        return homeBaseUrl + appendUrl;
    }

    /**
     * 申请书模板合成申请书 docx
     */
    public Path buildApplyFileByTemplate(String acceptOrderNo, ApplyTemplatePdfParams params) {
        try {
            ElgLogger.info(log, log -> log.info("{} >> 申请书模板合成开始", acceptOrderNo));
            Path sourceTemplate = getFileByRelativePath("template/01电子保函申请单文件模板.docx").toPath();
            Path targetDocx = buildSaveAbsolutePath("ofd", acceptOrderNo, acceptOrderNo + "Apply", "docx");
            targetDocx = DocFillUtil.fillDocTemplate(sourceTemplate, targetDocx, BeanMap.create(params));
            Path targetPdf = buildSaveAbsolutePath("ofd", acceptOrderNo, acceptOrderNo + "Apply", "pdf");
            DocFillUtil.doc2pdf(targetDocx, targetPdf, null);
            ElgLogger.info(log, log -> log.info("{} << 申请书模板合成完成", acceptOrderNo));
            return targetPdf;
        } catch (Exception e) {
            ElgLogger.error(log, log -> log.error("{} << 申请书模板合成异常:{}", acceptOrderNo, e.getMessage(), e));
            throw new RuntimeException("申请书模板填充失败");
        }
    }

    /**
     * 到账证明模板填充docx
     */
    public Path buildReceiveFileByTemplate(String acceptOrderNo, ReceiveTemplatePdfParams params) {
        try {
            ElgLogger.info(log, log -> log.info("{} >> 到账证明模板合成开始", acceptOrderNo));
            Path sourceTemplate = getFileByRelativePath("template/02到账证明文件模板.docx").toPath();
            Path targetDocx = buildSaveAbsolutePath("ofd", acceptOrderNo, "到账证明", "docx");
            targetDocx = DocFillUtil.fillDocTemplate(sourceTemplate, targetDocx, BeanMap.create(params));
            ElgLogger.info(log, log -> log.info("{} << 到账证明模板合成完成", acceptOrderNo));
            return targetDocx;
        } catch (Exception e) {
            ElgLogger.error(log, log -> log.error("{} << 到账证明模板合成异常:{}", acceptOrderNo, e.getMessage(), e));
            throw new RuntimeException("到账证明模板合成失败");
        }
    }

    /**
     * 保函模板填充docx
     */
    public Path buildGuaranteeFileByTemplate(String acceptOrderNo, GuaranteeTemplatePdfParams params) {
        try {
            ElgLogger.info(log, log -> log.info("{} >> 担保保函模板合成开始", acceptOrderNo));
            String templateFileName = params.getGuaranteeTemplateType().getTemplateFileName();
            Path sourceTemplate = getFileByRelativePath("template/" + templateFileName).toPath();
            Path targetDocx = buildSaveAbsolutePath("ofd", acceptOrderNo, "担保保函", "docx");
            targetDocx = DocFillUtil.fillDocTemplate(sourceTemplate, targetDocx, BeanMap.create(params));
            ElgLogger.info(log, log -> log.info("{} << 担保保函模板合成完成", acceptOrderNo));
            return targetDocx;
        } catch (Exception e) {
            ElgLogger.error(log, log -> log.error("{} << 担保保函模板合成异常:{}", acceptOrderNo, e.getMessage(), e));
            throw new RuntimeException("担保保函模板合成失败");
        }
    }

    /**
     * 保函模板填充docx
     */
    public Path buildGuaranteeFileByTemplate(String acceptOrderNo, GuaranteeTemplatePdfParams params,String fileName) {
        try {
            ElgLogger.info(log, log -> log.info("{} >> 担保保函模板合成开始", acceptOrderNo));
            String templateFileName = params.getGuaranteeTemplateType().getTemplateFileName();
            Path sourceTemplate = getFileByRelativePath("template/" + templateFileName).toPath();
            Path targetDocx = buildSaveAbsolutePath("ofd", acceptOrderNo, fileName, "docx");
            targetDocx = DocFillUtil.fillDocTemplate(sourceTemplate, targetDocx, BeanMap.create(params));
            ElgLogger.info(log, log -> log.info("{} << 担保保函模板合成完成", acceptOrderNo));
            return targetDocx;
        } catch (Exception e) {
            ElgLogger.error(log, log -> log.error("{} << 担保保函模板合成异常:{}", acceptOrderNo, e.getMessage(), e));
            throw new RuntimeException("担保保函模板合成失败");
        }
    }
    public void deleteFileByRelativePath(String relativePath) {
        if (StringUtils.isBlank(relativePath)) {
            log.warn("尝试删除文件，但提供的相对路径为空，操作已跳过。");
            return;
        }
        try {
            Path absolutePath = this.getAbsolutePath(relativePath);
            boolean deleted = Files.deleteIfExists(absolutePath);
            if (deleted) {
                log.info("成功删除物理文件: {}", absolutePath);
            } else {
                log.warn("尝试删除物理文件但文件不存在: {}", absolutePath);
            }
        } catch (IOException e) {
            log.error("删除物理文件时发生I/O异常，路径: {}", relativePath, e);
            throw new SystemRuntimeException(ErrorCode.ERROR, "删除物理文件失败: " + e.getMessage());
        } catch (Exception e) {
            log.error("删除物理文件时发生未知异常，路径: {}", relativePath, e);
            throw new SystemRuntimeException(ErrorCode.ERROR, "删除物理文件时发生未知错误: " + e.getMessage());
        }
    }
    public void deleteFilesByPrefix(String subPath, String curDir, String fileNamePrefix) {
        Path directoryPath = buildSaveDirectoryPath(subPath, curDir);

        if (Files.exists(directoryPath) && Files.isDirectory(directoryPath)) {
            try (DirectoryStream<Path> stream = Files.newDirectoryStream(directoryPath, fileNamePrefix + "*")) {
                for (Path entry : stream) {
                    try {
                        Files.delete(entry);
                        log.info("成功删除旧的理赔凭证文件: {}", entry.toString());
                    } catch (IOException e) {
                        log.error("删除文件失败: {}", entry.toString(), e);
                    }
                }
            } catch (IOException e) {
                log.error("遍历目录查找旧凭证文件时发生错误: 目录={}, 前缀={}", directoryPath, fileNamePrefix, e);
            }
        }
    }

    private Path buildSaveDirectoryPath(String subPath, String curDir) {
        if (this.resourceConfig == null) {
            throw new IllegalStateException("ElgResourceConfig is not initialized.");
        }
        String directoryRelativePath = subPath + File.separator + curDir;
        Path directoryAbsolutePath = Paths.get(resourceConfig.getBasePath(), directoryRelativePath);
        if (Files.notExists(directoryAbsolutePath)) {
            try {
                Files.createDirectories(directoryAbsolutePath);
            } catch (IOException e) {
                throw new RuntimeException("创建附件目录失败: " + directoryAbsolutePath, e);
            }
        }
        return directoryAbsolutePath;
    }

    public static void main(String[] args) {
        ElgResourceService elgResourceService = new ElgResourceService(null);
        elgResourceService.restTemplate = new RestTemplate();
        String remoteUrl = "https://bz.jf.uat.guogushu.com/api/static/bozhou/2025/03/05/湖南远程建设集团有限公司法人身份证人身面_20250305204451A012.jpg";
        remoteUrl = "https://ebg.fuebid.com/show.php?sss=ZpwORcGV9apO7B6tr9RYi4VMmiUFFMHVKBKdcwgHR1PCe3rXqErYBer%2FAniT1iC8jEfXt3KfmL%2FI2OcZMB3DYg6EDk2xCwSgBWmzpbvJ1iBS2rRBiAjNJWNxXbVI4MhBBBn0pihhIPK%2FxITkKrxVsAxk";
        Path path1 = elgResourceService.downloadFile(remoteUrl);
        Path path = elgResourceService.downloadByURL(remoteUrl);
        String fileType = elgResourceService.getFileType(path);

        Path targetPath = Paths.get("d:/test", "招标文件." + fileType);
        try {
            Files.copy(path, targetPath);
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("targetPath = " + targetPath);
//        try {
//            Files.probeContentType(Paths.get("d:/abc.pdf"));
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
    }
}
